# -*- coding: utf-8 -*-
# @Time    : 2024/7/8 10:01
# @Author  : yujiahao
# @File    : 08_fastapi_request_body_parameters.py
# @description:请求体

from typing import Annotated

from fastapi import FastAPI, Path, Body
from pydantic import BaseModel

app = FastAPI()



# 路径操作将期望一个具有 Item 的属性的 JSON 请求体,我们可以在这里弄一个类
class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


class User(BaseModel):
    username: str
    full_name: str | None = None

# todo 1、混合使用 Path、Query 和请求体参数
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User):
    '''
    - 可以声明有多个请求体参数（这里是两个pydantic模型参数）
    - 因此，它将使用参数名称作为请求体中的键（字段名称），并期望一个类似于以下内容的请求体：


        {
            "item": {
                "name": "Foo",
                "description": "The pretender",
                "price": 42.0,
                "tax": 3.2
            },
            "user": {
                "username": "dave",
                "full_name": "Dave Grohl"
            }
        }
    - FastAPI 将自动对请求中的数据进行转换，因此 item 参数将接收指定的内容，user 参数也是如此。
    '''
    results = {"item_id": item_id, "item": item, "user": user}
    return results


# todo 2、 请求体中的单一值


@app.put("/item/{item_id}")
async def update_item(
    item_id: int, item: Item, user: User, importance: Annotated[int, Body()]
):
    """
    与使用 Query 和 Path 为查询参数和路径参数定义额外数据的方式相同，
    FastAPI 提供了一个同等的 Body。

    例如，为了扩展先前的模型，你可能决定除了 item 和 user 之外，
    还想在同一请求体中具有另一个键 importance。

    如果你就按原样声明它，因为它是一个单一值，FastAPI 将假定它是一个查询参数。

    但是你可以使用 Body 指示 FastAPI 将其作为请求体的另一个键进行处理。
    Body 同样具有与 Query、Path 以及其他后面将看到的类完全相同的额外校验和元数据参数。


    希望得到这样的结果：也就是说和item同级别的单一值

    {
    "item": {
        "name": "Foo",
        "description": "The pretender",
        "price": 42.0,
        "tax": 3.2
    },
    "user": {
        "username": "dave",
        "full_name": "Dave Grohl"
    },
    "importance": 5
}
    """

    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    return results



# todo 3、多个请求体参数和查询参数

@app.put("/items_add_q/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item,
    user: User,
    importance: Annotated[int, Body(gt=0)],
    q: str | None = None,
):
    '''
    除了请求体参数外，还可以在任何需要的时候声明额外的查询参数。

    由于默认情况下单一值被解释为查询参数，因此不必显式地添加 Query，可以仅执行以上操作：
    直接在参数中添加    q:str | None = None

    '''
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    if q:
        results.update({"q": q})
    return results


# todo 4、嵌入单个请求体参数


@app.put("/items_single/{item_id}")
# async def update_item(item_id: int, item: Item):
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
    '''

    假设你只有一个来自 Pydantic 模型 Item 的请求体参数 item。

    默认情况下，FastAPI 将直接期望这样的请求体。

    但是，如果你希望它期望一个拥有 item 键并在值中包含模型内容的 JSON，就像在声明额外的请求体参数时所做的那样，
    则可以使用一个特殊的 Body 参数 embed：item: Item = Body(embed=True)

    '''

    results = {"item_id": item_id, "item": item}
    return results

